using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;
using SharpGL.Enumerations;

namespace SharpGL.OpenGLAttributes
{
    /// <summary>
    /// This class has all the settings you can edit for fog.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "ColorBufferAttributes", Namespace = "SharpGL.SceneGraph")]
    public class ColorBufferAttributes : OpenGLAttributes
    {
        #region Private Consts

        private static readonly AttributeMask attributeMask = AttributeMask.ColorBuffer;

        #endregion Private Consts

        #region Private Fields

        [DataMember()]
        private bool? enableAlphaTest;
        [DataMember()]
        private AlphaTestFunction? alphaTestFunction;
        [DataMember()]
        private float? alphaTestReferenceValue;
        [DataMember()]
        private bool? enableBlend;
        [DataMember()]
        private BlendingSourceFactor? blendingSourceFactor;
        [DataMember()]
        private BlendingDestinationFactor? blendingDestinationFactor;
        [DataMember()]
        private bool? enableDither;
        [DataMember()]
        private DrawBufferMode? drawBufferMode;
        [DataMember()]
        private bool? enableLogicOp;
        [DataMember()]
        private LogicOp? logicOp;
        [DataMember()]
        private GLColor? colorModeClearColor;
        [DataMember()]
        private GLColor? indexModeClearColor;
        [DataMember()]
        private GLColor? colorModeWriteMask;
        [DataMember()]
        private GLColor? indexModeWriteMask;

        #endregion Private Fields

        #region Protected Methods

        protected override void OnDeserializing()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorBufferAttributes"/> class.
        /// </summary>
        public ColorBufferAttributes()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Returns true if any attributes are set.
        /// </summary>
        /// <returns>
        /// True if any attributes are set
        /// </returns>
        public override bool AreAnyAttributesSet()
        {
            return
                enableAlphaTest.HasValue ||
                alphaTestFunction.HasValue ||
                alphaTestReferenceValue.HasValue ||
                enableBlend.HasValue ||
                blendingSourceFactor.HasValue ||
                blendingDestinationFactor.HasValue ||
                enableDither.HasValue ||
                drawBufferMode.HasValue ||
                enableLogicOp.HasValue ||
                logicOp.HasValue ||
                colorModeClearColor.HasValue ||
                indexModeClearColor.HasValue ||
                colorModeWriteMask.HasValue ||
                indexModeWriteMask.HasValue;
        }

        /// <summary>
        /// Reset all attributes to unset state.
        /// </summary>
        public override void ResetAllAttributes()
        {
            EnableAlphaTest = null;
            AlphaTestFunction = null;
            AlphaTestReferenceValue = null;
            EnableBlend = null;
            BlendingSourceFactor = null;
            BlendingDestinationFactor = null;
            EnableDither = null;
            DrawBufferMode = null;
            EnableLogicOp = null;
            LogicOp = null;
            ColorModeClearColor = null;
            IndexModeClearColor = null;
            ColorModeWriteMask = null;
            IndexModeWriteMask = null;
        }

        /// <summary>
        /// Sets the attributes.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        public override void SetAttributes(OpenGL gl)
        {
            if (enableAlphaTest.HasValue && alphaTestFunction.HasValue && alphaTestReferenceValue.HasValue)
            {
                gl.EnableIf(OpenGL.GL_ALPHA_TEST, enableAlphaTest.Value);
                gl.AlphaFunc(alphaTestFunction.Value, alphaTestReferenceValue.Value);
            }

            if (enableBlend.HasValue && blendingSourceFactor.HasValue && blendingDestinationFactor.HasValue)
            {
                gl.EnableIf(OpenGL.GL_BLEND, enableBlend.Value);
                gl.BlendFunc(blendingSourceFactor.Value, blendingDestinationFactor.Value);
            }

            if (enableDither.HasValue) gl.EnableIf(OpenGL.GL_DITHER, enableDither.Value);
            if (drawBufferMode.HasValue) gl.DrawBuffer(drawBufferMode.Value);

            if (enableLogicOp.HasValue && logicOp.HasValue)
            {
                gl.EnableIf(OpenGL.GL_COLOR_LOGIC_OP, enableLogicOp.Value);
                gl.LogicOp(logicOp.Value);
            }
            if (colorModeClearColor.HasValue) gl.ClearColor(colorModeClearColor.Value.R, colorModeClearColor.Value.G, colorModeClearColor.Value.B, colorModeClearColor.Value.A);
            //todowritemask
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the enable alpha test.
        /// </summary>
        /// <value>
        /// The enable alpha test.
        /// </value>
        [Description("EnableAlphaTest"), Category("Color Buffer attributes")]
        public bool? EnableAlphaTest
        {
            get { return enableAlphaTest; }
            set
            {
                if (enableAlphaTest != value)
                {
                    enableAlphaTest = value;

                    NotifyPropertyChanged("EnableAlphaTest");
                }
            }
        }

        /// <summary>
        /// Gets or sets the alpha test function.
        /// </summary>
        /// <value>
        /// The alpha test function.
        /// </value>
        [Description("AlphaTestFunction"), Category("Color Buffer attributes")]
        public AlphaTestFunction? AlphaTestFunction
        {
            get { return alphaTestFunction; }
            set
            {
                if (alphaTestFunction != value)
                {
                    alphaTestFunction = value;

                    NotifyPropertyChanged("AlphaTestFunction");
                }
            }
        }

        /// <summary>
        /// Gets or sets the alpha test reference value.
        /// </summary>
        /// <value>
        /// The alpha test reference value.
        /// </value>
        [Description("AlphaTestReferenceValue"), Category("Color Buffer attributes")]
        public float? AlphaTestReferenceValue
        {
            get { return alphaTestReferenceValue; }
            set
            {
                if (alphaTestReferenceValue != value)
                {
                    alphaTestReferenceValue = value;

                    NotifyPropertyChanged("AlphaTestReferenceValue");
                }
            }
        }

        /// <summary>
        /// Gets or sets the enable blend.
        /// </summary>
        /// <value>
        /// The enable blend.
        /// </value>
        [Description("EnableBlend"), Category("Color Buffer attributes")]
        public bool? EnableBlend
        {
            get { return enableBlend; }
            set
            {
                if (enableBlend != value)
                {
                    enableBlend = value;

                    NotifyPropertyChanged("EnableBlend");
                }
            }
        }

        /// <summary>
        /// Gets or sets the blending source factor.
        /// </summary>
        /// <value>
        /// The blending source factor.
        /// </value>
        [Description("BlendingSourceFactor"), Category("Color Buffer attributes")]
        public BlendingSourceFactor? BlendingSourceFactor
        {
            get { return blendingSourceFactor; }
            set
            {
                if (blendingSourceFactor != value)
                {
                    blendingSourceFactor = value;

                    NotifyPropertyChanged("BlendingSourceFactor");
                }
            }
        }

        /// <summary>
        /// Gets or sets the blending destination factor.
        /// </summary>
        /// <value>
        /// The blending destination factor.
        /// </value>
        [Description("BlendingDestinationFactor"), Category("Color Buffer attributes")]
        public BlendingDestinationFactor? BlendingDestinationFactor
        {
            get { return blendingDestinationFactor; }
            set
            {
                if (blendingDestinationFactor != value)
                {
                    blendingDestinationFactor = value;

                    NotifyPropertyChanged("BlendingDestinationFactor");
                }
            }
        }

        /// <summary>
        /// Gets or sets the enable dither.
        /// </summary>
        /// <value>
        /// The enable dither.
        /// </value>
        [Description("EnableDither"), Category("Color Buffer attributes")]
        public bool? EnableDither
        {
            get { return enableDither; }
            set
            {
                if (enableDither != value)
                {
                    enableDither = value;

                    NotifyPropertyChanged("EnableDither");
                }
            }
        }

        /// <summary>
        /// Gets or sets the draw buffer mode.
        /// </summary>
        /// <value>
        /// The draw buffer mode.
        /// </value>
        [Description("DrawBufferMode"), Category("Color Buffer attributes")]
        public DrawBufferMode? DrawBufferMode
        {
            get { return drawBufferMode; }
            set
            {
                if (drawBufferMode != value)
                {
                    drawBufferMode = value;

                    NotifyPropertyChanged("DrawBufferMode");
                }
            }
        }

        /// <summary>
        /// Gets or sets the enable logic op.
        /// </summary>
        /// <value>
        /// The enable logic op.
        /// </value>
        [Description("EnableLogicOp"), Category("Color Buffer attributes")]
        public bool? EnableLogicOp
        {
            get { return enableLogicOp; }
            set
            {
                if (enableLogicOp != value)
                {
                    enableLogicOp = value;

                    NotifyPropertyChanged("EnableLogicOp");
                }
            }
        }

        /// <summary>
        /// Gets or sets the logic op.
        /// </summary>
        /// <value>
        /// The logic op.
        /// </value>
        [Description("LogicOp"), Category("Color Buffer attributes")]
        public LogicOp? LogicOp
        {
            get { return logicOp; }
            set
            {
                if (logicOp != value)
                {
                    logicOp = value;

                    NotifyPropertyChanged("LogicOp");
                }
            }
        }

        /// <summary>
        /// Gets or sets the color of the color mode clear.
        /// </summary>
        /// <value>
        /// The color of the color mode clear.
        /// </value>
        [Description("ColorModeClearColor"), Category("Color Buffer attributes")]
        public GLColor? ColorModeClearColor
        {
            get { return colorModeClearColor; }
            set
            {
                if (colorModeClearColor != value)
                {
                    colorModeClearColor = value;

                    NotifyPropertyChanged("ColorModeClearColor");
                }
            }
        }

        /// <summary>
        /// Gets or sets the color of the index mode clear.
        /// </summary>
        /// <value>
        /// The color of the index mode clear.
        /// </value>
        [Description("IndexModeClearColor"), Category("Color Buffer attributes")]
        public GLColor? IndexModeClearColor
        {
            get { return indexModeClearColor; }
            set
            {
                if (indexModeClearColor != value)
                {
                    indexModeClearColor = value;

                    NotifyPropertyChanged("IndexModeClearColor");
                }
            }
        }

        /// <summary>
        /// Gets or sets the color mode write mask.
        /// </summary>
        /// <value>
        /// The color mode write mask.
        /// </value>
        [Description("ColorModeWriteMask"), Category("Color Buffer attributes")]
        public GLColor? ColorModeWriteMask
        {
            get { return colorModeWriteMask; }
            set
            {
                if (colorModeWriteMask != value)
                {
                    colorModeWriteMask = value;

                    NotifyPropertyChanged("ColorModeWriteMask");
                }
            }
        }

        /// <summary>
        /// Gets or sets the index mode write mask.
        /// </summary>
        /// <value>
        /// The index mode write mask.
        /// </value>
        [Description("IndexModeWriteMask"), Category("Color Buffer attributes")]
        public GLColor? IndexModeWriteMask
        {
            get { return indexModeWriteMask; }
            set
            {
                if (indexModeWriteMask != value)
                {
                    indexModeWriteMask = value;

                    NotifyPropertyChanged("IndexModeWriteMask");
                }
            }
        }

        #endregion Public Properties
    }
}
